﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AnnotateMe.Interfaces;

namespace AnnotateMe.Logic
{
    /// <summary>
    /// This layout service assumes all blocks form one line and are ordered from left to right.
    /// </summary>
    public class SimpleLayoutService : ILayoutService
    {
        private Func<ImmutablePoint, ImmutablePoint, Shape> connectorFactory;

        public SimpleLayoutService(Func<ImmutablePoint, ImmutablePoint, Shape> connectorFactory)
        {
            this.connectorFactory = connectorFactory;
        }

        public CompositeShape Arrange(IList<PossiblyAnnotatedBlock> possiblyAnnotatedBlocks)
        {
            var placedAnnotationRectangles = new List<ImmutableRectangle>();
            var shapes = new List<Shape>();
            foreach (var block in possiblyAnnotatedBlocks)
            {
                // for blocks without annotation just yield content rectangle
                if (!block.HasAnnotation)
                {
                    shapes.Add(block.ContentRectangle);
                    continue;
                }

                // otherwise place the annotation block and yield a composite shape

                //   calculate mean x for content block and use as mean x for annotation block
                double meanX = block.ContentRectangle.OriginPoint.X + block.ContentRectangle.Size.Width / 2;
                double annoationX = meanX - block.AnnotationRectangle.Size.Width / 2;
                
                double contentY = block.ContentRectangle.OriginPoint.Y;
                double contentHeight = block.ContentRectangle.Size.Height;
                double annotationHeight = block.AnnotationRectangle.Size.Height;

                const double pixelPerLevel = 20;
                for (int level = 1; level <= 20; level++)
                {
                    double pixelOffset = pixelPerLevel * level;
                    bool placed = false;

                    foreach (var aboveContent in new[] {true, false})
                    {
                        double annotaionY = aboveContent ? contentY - pixelOffset - annotationHeight : contentY + contentHeight + pixelOffset;

                        var possibleAnnotationOrigin = new ImmutablePoint(annoationX, annotaionY);
                        var possibleAnnotationRectangle = block.AnnotationRectangle.WithOrigin(possibleAnnotationOrigin);

                        placed = placedAnnotationRectangles.All(r => !r.IntersectsWith(possibleAnnotationRectangle));

                        if (placed)
                        {
                            double annotationConnectorY = aboveContent ? annotaionY + annotationHeight : annotaionY;
                            double contentConnectorY = aboveContent ? contentY : contentY + contentHeight;
                            
                            var connectorStart = new ImmutablePoint(meanX, annotationConnectorY);
                            var connectorEnd = new ImmutablePoint(meanX, contentConnectorY);

                            var connector = this.connectorFactory(connectorStart, connectorEnd);

                            shapes.Add(new CompositeShape(new Shape[] { block.ContentRectangle, connector, possibleAnnotationRectangle }));
                            
                            placedAnnotationRectangles.Add(possibleAnnotationRectangle);
                            break;
                        }
                    }

                    if(placed)
                        break;
                }
            }

            return new CompositeShape(shapes);
        }
    }
}
